package com.literaryfamily.literaryfamily.service.user.security.impl;

import com.literaryfamily.literaryfamily.dao.UserVerificationCodeMapper;
import com.literaryfamily.literaryfamily.entity.UserVerificationCode;
import com.literaryfamily.literaryfamily.entity.UserVerificationCodeExample;
import com.literaryfamily.literaryfamily.enumPackage.CodeType;
import com.literaryfamily.literaryfamily.exceptions.OperationException;
import com.literaryfamily.literaryfamily.exceptions.WriteError;
import com.literaryfamily.literaryfamily.myUtil.LogUtil;
import com.literaryfamily.literaryfamily.myUtil.StringUtil;
import com.literaryfamily.literaryfamily.service.user.security.VerifyCodeService;
import io.micrometer.common.lang.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.security.SecureRandom;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import static com.literaryfamily.literaryfamily.constant.Constant.VERIFICATION_CODE_EXPIRATION_TIME;

@Service
@Transactional(noRollbackFor = OperationException.class)
public class VerifyCodeServiceImpl implements VerifyCodeService {
    private static final String SMS_URL = "https://push.spug.cc/send/yWYXwm6kNOjb1VZ2";
    @Autowired
    UserVerificationCodeMapper userVerificationCodeMapper;
    @Autowired
    private RestTemplate restTemplate;

    // 中国手机号正则表达式
    private static final String CHINA_PHONE_PATTERN = "^1[3-9]\\d{9}$";
    private static final Pattern PHONE_PATTERN = Pattern.compile(CHINA_PHONE_PATTERN);

    /**
     * 验证手机号格式是否正确
     *
     * @param phoneNumber 要验证的手机号
     * @return 如果手机号格式正确返回true，否则返回false
     */
    public static boolean isValidChinesePhoneNumber(String phoneNumber) {
        if (StringUtil.isNull(phoneNumber)) {
            return false;
        }
        return PHONE_PATTERN.matcher(phoneNumber).matches();
    }

    @Override
    public UserVerificationCode sendVerificationCode(String mobile, Long userId, int type) {
        //检查手机号码格式
        if (!isValidChinesePhoneNumber(mobile)) throw new OperationException("手机号格式错误");
        //检查是否重复
        UserVerificationCodeExample userVerificationCodeExample = new UserVerificationCodeExample();
        //检查是否存在手机号,用途类型与当前完全相同的
        userVerificationCodeExample.createCriteria()
                .andPhoneEqualTo(mobile)
                .andUseTypeEqualTo(type)
                .andExpirationTimeGreaterThan(new Date())
                .andValidityEqualTo(true)
        ;
        UserVerificationCode verificationCode;
        List<UserVerificationCode> result = userVerificationCodeMapper.selectByExample(userVerificationCodeExample);
        //不匹配时会抛出操作错误,保证合法性
        CodeType code1 = CodeType.getCode(type);
        Date now = new Date();
        if (!result.isEmpty()) {
            //重复,延迟长时间并重新发送
            verificationCode = result.get(0);
            //检查发送时间是否在失效之内
            if (now.getTime() - verificationCode.getTransactionTime().getTime() < VERIFICATION_CODE_EXPIRATION_TIME)
                throw new OperationException("操作过于频繁");
            verificationCode.setValidity(true);
            verificationCode.setTransactionTime(now);
            verificationCode.setExpirationTime(new Date(now.getTime() + VERIFICATION_CODE_EXPIRATION_TIME));
            WriteError.tryWrite(userVerificationCodeMapper.updateByExample(verificationCode, userVerificationCodeExample));
        } else {
            SecureRandom random = new SecureRandom();
            int number = random.nextInt(100_000_000);
            verificationCode = new UserVerificationCode();
            verificationCode.setUserId(userId);
            verificationCode.setVerificationCode(String.format("%08d", number));
            verificationCode.setTransactionTime(now);
            verificationCode.setExpirationTime(new Date(now.getTime() + VERIFICATION_CODE_EXPIRATION_TIME));
            verificationCode.setUseType(type);
            verificationCode.setValidity(true);
            verificationCode.setPhone(mobile);
            WriteError.tryWrite(userVerificationCodeMapper.insert(verificationCode));
        }
        try {
            //发送短信,构造 URL（单位为分钟）
            long minutes = VERIFICATION_CODE_EXPIRATION_TIME / 1000 / 60;
            Map<String, Object> body = new HashMap<>();
            body.put("name", code1.getTypeName());
            body.put("code", verificationCode.getVerificationCode());
            body.put("time", minutes);
            body.put("targets", mobile);
            restTemplate.postForObject(SMS_URL, body, String.class);
            LogUtil.info(getClass(), String.format("发送短信: phone=%s, code=%s, type=%s", mobile, verificationCode.getVerificationCode(), code1.getTypeName()));
        } catch (Exception e) {
            verificationCode.setValidity(false);
            UserVerificationCodeExample example = new UserVerificationCodeExample();
            example.createCriteria()
                    .andPhoneEqualTo(mobile)
                    .andUserIdEqualTo(userId)
                    .andUseTypeEqualTo(type)
                    .andVerificationCodeEqualTo(verificationCode.getVerificationCode())
            ;

            userVerificationCodeMapper.updateByExampleSelective(verificationCode, example);
            throw new OperationException("短信发送失败");
        }
        return verificationCode;
    }

    @Override
    public UserVerificationCode validateSmsCode(@Nullable Long userId, String mobile, String verifyCode, int type) {
        UserVerificationCodeExample userVerificationCodeExample = new UserVerificationCodeExample();
        userVerificationCodeExample.createCriteria()
                .andPhoneEqualTo(mobile)
                .andVerificationCodeEqualTo(verifyCode)
                .andValidityEqualTo(true)
                .andExpirationTimeGreaterThan(new Date())
        ;
        if (userId == null) {
            if (type == CodeType.REGISTER.getCode()) {
                userVerificationCodeExample.createCriteria()
                        .andUseTypeEqualTo(CodeType.REGISTER.getCode());
            } else
                throw new OperationException("错误!!不存在的用户");
        } else {
            userVerificationCodeExample.createCriteria()
                    .andUserIdEqualTo(userId)
                    .andUseTypeEqualTo(type)
            ;
        }
        List<UserVerificationCode> result = userVerificationCodeMapper.selectByExample(userVerificationCodeExample);
        if (result.size() == 1) {
            //验证成功更新状态
            UserVerificationCode verificationCode = result.get(0);
            verificationCode.setValidity(false);
            WriteError.tryWrite(userVerificationCodeMapper.updateByExampleSelective(verificationCode, userVerificationCodeExample));
            return result.get(0);
        }
        throw new OperationException("验证码错误");
    }
}